﻿using System;
using System.Collections.Generic;
using System.Xml;
using NeuralNetwork.OutputTypes;
using NeuralNetwork.Neurons;

namespace NeuralNetwork.Layers
{
    public class OutputLayer : Layer
    {
        public OutputLayer(Network network)
        {
            this.network = network;
            this.forward = null;
            this.ID = network.GetUniqueID();
            network.output = this;
        }

        public OutputLayer(Network network, List<Output> outputs, string neurontype): this(network)
        {
            Neuron on = null;
            for (int i = 0; i < outputs.Count; i++)
            {
                on = neuronFactory.Make(neurontype, network);
                if (on is OutputNeuron)
                {
                    ((OutputNeuron)on).Output = outputs[i];
                    neurons.Add(on);
                }
            }        
        }

        virtual public List<Output> Result()
        {
            List<Output> result = new List<Output>();
            foreach (OutputNeuron on in neurons)
            {
                if (on.Check()) result.Add(on.Output);
            }        
            
            network.log.PrintList("result", result);
            return result;
        }


        virtual public double Error(List<Output> expected)
        {
            network.log.PrintList("expected", expected);

            if (expected.Count != neurons.Count)
            {
                throw new RankException("Expected output needs to be equal the number neurons in the output layer");                
            }

            OutputNeuron on = null;
            double error = 0;
            for (int i = 0; i < neurons.Count; i++)
            { 
                on = (OutputNeuron)neurons[i];
                if (expected[i] != null)
                    on.Error = expected[i].ToDouble() - on.Value;
                else
                    on.Error = -on.Value;

                error += on.Error;
            }

            return error; 
        }

        public override void Prune()
        { 
            // We never Prune the outputlayer
        }
    }
}
